// fastEasy - 数组与对象处理工具库
// 提供常用的数组与对象操作方法，提升开发效率

/**
 * 数组处理工具
 */
const array = {
  /**
   * 去重数组
   * @param {T[]} arr - 要去重的数组
   * @returns {T[]} 去重后的数组
   */
  unique: <T>(arr: T[]): T[] => {
    if (!Array.isArray(arr)) {
      throw new TypeError('Expected an array');
    }
    return [...new Set(arr)];
  },

  /**
   * 打乱数组
   * @param {T[]} arr - 要打乱的数组
   * @returns {T[]} 打乱后的数组
   */
  shuffle: <T>(arr: T[]): T[] => {
    if (!Array.isArray(arr)) {
      throw new TypeError('Expected an array');
    }
    const newArr = [...arr];
    for (let i = newArr.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [newArr[i], newArr[j]] = [newArr[j]!, newArr[i]!];
    }
    return newArr;
  },

  /**
   * 分割数组
   * @param {T[]} arr - 要分割的数组
   * @param {number} size - 每个子数组的大小
   * @returns {T[][]} 分割后的二维数组
   */
  chunk: <T>(arr: T[], size: number): T[][] => {
    if (!Array.isArray(arr)) {
      throw new TypeError('Expected an array');
    }
    if (typeof size !== 'number' || size <= 0) {
      throw new TypeError('Size must be a positive number');
    }
    const result: T[][] = [];
    for (let i = 0; i < arr.length; i += size) {
      result.push(arr.slice(i, i + size));
    }
    return result;
  },

  /**
   * 扁平化数组
   * @param {any[]} arr - 要扁平化的数组
   * @returns {T[]} 扁平化后的数组
   */
  flatten: <T>(arr: T[][]): T[] => {
    if (!Array.isArray(arr)) {
      throw new TypeError('Expected an array');
    }
    return arr.flat(Infinity) as T[];
  },

  /**
   * 判断数组是否包含另一个数组的所有元素
   * @param {T[]} arr - 原数组
   * @param {T[]} target - 要检查的目标数组
   * @returns {boolean} 是否包含所有元素
   */
  includesAll: <T>(arr: T[], target: T[]): boolean => {
    if (!Array.isArray(arr) || !Array.isArray(target)) {
      throw new TypeError('Expected arrays');
    }
    return target.every(item => arr.includes(item));
  },
};

/**
 * 对象处理工具
 */
const object = {
  /**
   * 深度合并对象
   * @param {object} target - 目标对象
   * @param {...object} sources - 源对象
   * @returns {object} 合并后的对象
   */
  merge: <T extends object>(target: T, ...sources: object[]): T => {
    if (target === null || typeof target !== 'object') {
      throw new TypeError('Target must be an object');
    }

    sources.forEach(source => {
      if (source === null || typeof source !== 'object') {
        return;
      }

      Object.keys(source).forEach(key => {
        const targetValue = target[key as keyof T];
        const sourceValue = (source as Record<string, unknown>)[key];

        if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
          (target as Record<string, unknown>)[key] = [...targetValue, ...sourceValue];
        } else if (
          typeof targetValue === 'object' &&
          targetValue !== null &&
          typeof sourceValue === 'object' &&
          sourceValue !== null
        ) {
          target[key as keyof T] = object.merge({ ...targetValue }, sourceValue);
        } else {
          (target as Record<string, unknown>)[key] = sourceValue;
        }
      });
    });

    return target;
  },

  /**
   * 获取对象的嵌套属性
   * @param {object} obj - 目标对象
   * @param {string|string[]} path - 属性路径，如 'a.b.c' 或 ['a', 'b', 'c']
   * @param {T} defaultValue - 默认值
   * @returns {T} 属性值或默认值
   */
  get: <T>(obj: object, path: string | string[], defaultValue?: T): T => {
    if (obj === null || typeof obj !== 'object') {
      return defaultValue as T;
    }

    const keys = Array.isArray(path) ? path : path.split('.');
    let result: unknown = obj;

    for (const key of keys) {
      if (
        result === null ||
        result === undefined ||
        typeof result !== 'object' ||
        !Object.prototype.hasOwnProperty.call(result, key)
      ) {
        return defaultValue as T;
      }
      result = (result as Record<string, unknown>)[key];
    }

    return result as T;
  },

  /**
   * 设置对象的嵌套属性
   * @param {object} obj - 目标对象
   * @param {string|string[]} path - 属性路径，如 'a.b.c' 或 ['a', 'b', 'c']
   * @param {T} value - 要设置的值
   * @returns {object} 修改后的对象
   */
  set: <T>(obj: object, path: string | string[], value: T): object => {
    if (obj === null || typeof obj !== 'object') {
      throw new TypeError('Target must be an object');
    }

    const keys = Array.isArray(path) ? path : path.split('.');
    let current: Record<string, unknown> = obj as Record<string, unknown>;

    for (let i = 0; i < keys.length - 1; i++) {
      const key = keys[i] as string;
      const keyValue = current[key];
      if (keyValue === null || keyValue === undefined || typeof keyValue !== 'object') {
        current[key] = {};
      }
      current = current[key] as Record<string, unknown>;
    }

    current[keys[keys.length - 1]!] = value;
    return obj;
  },

  /**
   * 深拷贝对象
   * @param {T} obj - 要拷贝的对象
   * @returns {T} 拷贝后的对象
   */
  cloneDeep: <T>(value: T): T => {
    if (value === null || typeof value !== 'object') {
      return value;
    }

    if (value instanceof Date) {
      return new Date(value.getTime()) as unknown as T;
    }

    if (Object.prototype.toString.call(value) === '[object RegExp]') {
      const regex = value as unknown as RegExp;
      return new RegExp(regex.source, regex.flags) as unknown as T;
    }

    if (Array.isArray(value)) {
      return value.map((item: T) => object.cloneDeep(item)) as unknown as T;
    }

    if (typeof value === 'object') {
      const cloned: Record<string, unknown> = {};
      for (const key in value) {
        if (Object.prototype.hasOwnProperty.call(value, key)) {
          cloned[key] = object.cloneDeep(value[key]);
        }
      }
      return cloned as unknown as T;
    }

    return value;
  },
};

// 导出所有工具
export { array, object };

export const { unique, shuffle, chunk, flatten, includesAll } = array;
export const { merge, get, set, cloneDeep } = object;

// 默认导出
export default {
  array,
  object,
  unique,
  shuffle,
  chunk,
  flatten,
  merge,
  get,
  set,
  cloneDeep,
};
